package com.gragra.data;
import java.io.BufferedReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import com.gragra.structures.Structure;
import com.gragra.structures.StructureGenerator;
import com.gragra.util.FileLineForEach;
/**
 * A simple Baseline implementation of the Corpus interface. Useful if all data can be
 * held in the memory.
 * @author Christoph Teichmann
 * @version 0.1
 */
public class CorpusBaseImplementation<Type extends Structure> implements Corpus<Type>
{
	/* (non-Javadoc)
	 * @see java.lang.Object#toString()
	 */
	@Override
	public String toString()
	{
		StringBuilder builder = new StringBuilder();
		builder.append("CorpusBaseImplementation [data=");
		builder.append(data);
		builder.append("]");
		return builder.toString();
	}
	/**
	 * constructs an empty corpus
	 */
	public CorpusBaseImplementation()
	{this.immut = Collections.unmodifiableCollection(data);}
	/**
	 * the collection of all the data in the corpus
	 */
	private final ArrayList<Type> data = 
										new ArrayList<Type>();
	/**
	 * an immutable view on the data, this is used in ensuring that
	 * the data can only be changed via the corpus methods
	 */
	private final Collection<Type> immut;
	/**
	 * method for adding data by reading strings line for line from the
	 * given BufferedReader, it is assumed that every line corresponds to a
	 * data point
	 * @param sG
	 * @param input
	 * @throws IOException
	 */
	public final void addData(final StructureGenerator<Type> sG,final BufferedReader input) 
													throws IOException
	{
		new FileLineForEach(input)
		{
			public void apply(String line)
			{addData(sG,line);}
		};
	}
	/**
	 * method for adding data from an Iterable of strings where every string
	 * represents an additional data point
	 * @param sG
	 * @param input
	 */
	public final void addData(StructureGenerator<Type> sG, Iterable<String> input)
	{
		for(String s : input)
		{addData(sG,s);}
	}
	/**
	 * method used to add a single datapoint represented by a string to the
	 * corpus, the structureGenerator defines how a string is turned into a
	 * structure datapoint
	 * @param sG
	 * @param input
	 */
	public final void addData(StructureGenerator<Type> sG, String input)
	{this.addData(sG.make(input));}
	/**
	 * this method adds a single datapoint to the corpus, all other ways to
	 * add data make use of this method, extending subclasses should override
	 * this method to change how data is handled.
	 * @param s
	 */
	public void addData(Type s)
	{this.data.add(s);}
	/**
	 * adds all the structures in the given collection to the corpus
	 * @param sG
	 * @param input
	 */
	public final void addData(Iterable<Type> input)
	{
		for(Type s : input)
		{this.addData(s);}
	}
	/**
	 * returns an int representing the number of datapoints in the corpus
	 * @return
	 */
	public int size()
	{return data.size();}
	/**
	 * returns the structure that this corpus contains at position i,
	 * for efficiency reasons, this is the original structure and not
	 * a copy, therefore the operations that are applied to it should
	 * never change anything that is meant to stay constant within this
	 * structure
	 * @param i
	 * @return
	 */
	public Type getEntry(int i)
	{return data.get(i);}
	/* (non-Javadoc)
	 * @see java.lang.Iterable#iterator()
	 */
	@Override
	public Iterator<Type> iterator()
	{return immut.iterator();}
}